﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;


namespace knetcat
{
    /// <summary>
    /// 这个类是个异步流类,最大的特点是，当一个流异步读取的时候，会直接将数据输出到另一个流
    /// 输出到另一个流有两种方式，一种是如下的Write接口，这个会调用真正的Write
    /// 另一种是如下的oppersiteRead接口，这个将数据做处理后会调用真正的Write
    /// </summary>
    public  class clsAsyncStream 
    {
        public int bufSize = 1024;//一次读取多少个字节

        private clsAsyncStream _oppersiteStream;
        /// <summary>
        /// 对方流，是和这个通讯的对方流
        /// </summary>
        public clsAsyncStream oppersiteStream
        {
            get { return _oppersiteStream; }
            set { _oppersiteStream = value; }
        }
        private Stream _myStream;
        /// <summary>
        /// 自己流
        /// </summary>
        public Stream myStream
        {
            get { return _myStream; }
            set { _myStream = value; }
        }

        /// <summary>
        /// 是否是传输文件，当传输成功后，就自动的关闭的
        /// </summary>
        public static bool isTransferFile { get; set; }

        /// <summary>
        /// 开始一个线程，获得流，并且不断的读取数据的
        /// </summary>
        public virtual void start()
        {
            Thread t = new Thread(asyncThread);
            t.IsBackground = true;
            t.Start();
        }

        /// <summary>
        /// 异步线程接口
        /// 这个方法主要做两件事情，
        /// 1、获得一个stream给myStream，这样就可以通过这个myStream发送信息了
        /// 2、死循环，不断的读取数据
        /// </summary>
        public virtual void asyncThread()
        {

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        public virtual void Write(byte[] buffer, int offset, int count)
        {
            try
            {
                if (myStream != null)
                {
                    lock (myStream)
                    {
                        myStream.Write(buffer, offset, count);
                    }
                }
            }
            catch (Exception e)
            {

                throw;
            }

        }

        /// <summary>
        /// 这个类表示对输入流输入的数据做相关操作的
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public virtual byte[] doSomething(byte[] buffer, int offset, int count)
        {
            //这里只是单纯的复制
            byte[] byte_return = new byte[count - offset];

            int intIndex = 0;

            for (int i = offset; i < count; i++)
            {
                byte_return[intIndex++] = buffer[i];
            }

            return byte_return;
        }
        

        /// <summary>
        /// 这个是有对方流发送的数据，这个类可以做相应的处理后再发出
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        public virtual void oppersiteRead(byte[] buffer, int offset, int count)
        {
            try
            {
                if (myStream != null)
                {
                    lock (myStream)
                    {
                        byte[] buf = doSomething(buffer, offset, count);
                        myStream.Write(buf, 0, buf.Count());
                    }
                }
            }
            catch (Exception e)
            {

                throw;
            }
        }

        /// <summary>
        /// 这个是查询输入的线程
        /// </summary>
        /// <param name="stream"></param>
        protected void readThread()
        {
            if (myStream!=null)
            {
                byte[] bytes = new byte[bufSize];


                try
                {
                    

                    int recv;
                    while ((recv = (myStream).Read(bytes, 0, bytes.Length))>0)
                    {
                        oppersiteStream.oppersiteRead(bytes, 0, recv);
                        Array.Clear(bytes, 0, bytes.Length);//清空
                    }

                }
                catch (Exception e)
                {
                    System.Console.WriteLine("流错误：" + e.Message);
                    //throw;
                }
                //如果是传输文件，传输完毕就关闭啦。
                if (isTransferFile)
                {
                    Environment.Exit(0);
                }
                
                
            }

        }


    }
    /// <summary>
    /// 实现和标准输入输入的
    /// </summary>
    public class clsAsyncStreamConsole : clsAsyncStream
    {
        public override void start()
        {
            Thread t = new Thread(stdioThreading);
            t.IsBackground = true;//后台线程啦
            t.Start();
            //base.start(obj);
        }


        public override void oppersiteRead(byte[] buffer, int offset, int count)
        {
            //这里其实还要判断编码的
            string str = System.Text.Encoding.Default.GetString(buffer);

            //截断字符串，因为后边的'\0'，不是我所需要的
            int i = str.IndexOf('\0');
            if (i >= 0)
            {
                str = str.Remove(i);
            }

            System.Console.Write(str);//这个字符界面的就直接只输出

            //base.oppersiteRead(buffer, offset, count);
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            //这里其实还要判断编码的
            string str = System.Text.Encoding.Default.GetString(buffer);

            //截断字符串，因为后边的'\0'，不是我所需要的
            int i = str.IndexOf('\0');
            if (i >= 0)
            {
                str = str.Remove(i);
            }
            //去掉最后一个回车
            if (str.Substring(str.Length - 1) == "\n")
            {
                str = str.Remove(str.Length - 1);
            }

            System.Console.WriteLine(str);//这个字符界面的就直接只输出
            //base.Write(buffer, offset, count);
        }
        /// <summary>
        /// 查询输入的线程
        /// </summary>
        private void stdioThreading()
        {
            //这个会不断的查询输入，并且将数据发送给
            while (true)
            {
                string str = System.Console.ReadLine()+Environment.NewLine;
                byte[] byteArray = System.Text.Encoding.Default.GetBytes(str);
                oppersiteStream.oppersiteRead(byteArray, 0, byteArray.Length);
                                
            }
        }

    }

    /// <summary>
    /// 这个是TCP的监听类
    /// </summary>
    public class clsAsyncStreamTcpListenr : clsAsyncStream
    {
        
        private int _port;
        /// <summary>
        /// 监听端口
        /// </summary>
        public int localPort
        {
            get { return _port; }
            set { _port = value; }
        }


        public override void asyncThread()
        {
            TcpListener server = null;
            try
            {
                // Set the TcpListener on port 13000.

                IPAddress localAddr = IPAddress.Parse("127.0.0.1");

                // TcpListener server = new TcpListener(port);
                server = new TcpListener(localAddr, localPort);

                // Start listening for client requests.
                server.Start();

                //Console.WriteLine("等待连接");

                Thread tRead = null;

                TcpClient tcpClientNew = null, tcpClientOld = null;
                // Enter the listening loop.
                do
                {
                    // Perform a blocking call to accept requests.
                    // You could also user server.AcceptSocket() here.
                    tcpClientNew = server.AcceptTcpClient();//一个新的连接

                    //如果还在读取数据
                    if ((tRead != null)&&(tRead.IsAlive))
                    {
                        //就关掉新的连接,同一时间只能有一个连接，且旧连接有线
                        tcpClientNew.Close();
                        continue;
                    }

                    if (tcpClientOld != null)
                    {
                        tcpClientOld.Close();//旧的连接关闭，
                        myStream.Close();//流关闭
                    }

                    tcpClientOld = tcpClientNew;//保存新连接
                    // Get a stream object for reading and writing
                    myStream = tcpClientNew.GetStream();

                    //一直读取数据直到异常出现
                    //这个读取还得开一个线程的原因是，
                    //如果不开线程，在这里循环读取,结果就是别的客户端连接上，但却不能执行到 AcceptTcpClient 这里，所以才
                    tRead = new Thread(readThread);
                    tRead.Start();

                } while (true);//默认一直循环

            }
            catch (SocketException e)
            {
                Console.WriteLine("SocketException: {0}", e);
            }
            finally
            {
                // Stop listening for new clients.
                server.Stop();

            }

            //base.asyncThread();
        }
        


    }

    /// <summary>
    /// 这个是TCP连接服务器类
    /// </summary>
    public class clsAsyncStreamTcpClient : clsAsyncStream
    {
        private int _localPort;
        /// <summary>
        /// 本地源端口
        /// </summary>
        public int localPort
        {
            get { return _localPort; }
            set { _localPort = value; }
        }

        private string _hostName;
        /// <summary>
        /// 目标
        /// </summary>
        public string hostName
        {
            get { return _hostName; }
            set { _hostName = value; }
        }

        private int _targetPort;
        /// <summary>
        /// 目标端口
        /// </summary>
        public int targetPort
        {
            get { return _targetPort; }
            set { _targetPort = value; }
        }

        public override void asyncThread()
        {
            IPAddress ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
            IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, localPort);//绑定到本地制定的端口，如果没有赋值，就是随机端口
            TcpClient tcpClientA = new TcpClient(ipLocalEndPoint);

            tcpClientA.Connect(hostName, targetPort);

            myStream = tcpClientA.GetStream();

            //读取文件啦,这个不用新建一个线程，因为这个是客户端。
            readThread();
            //base.asyncThread();
        }

    }

    /// <summary>
    /// udp的监听类，UDP是没有流概念的，所以要做多个更改
    /// </summary>
    public class clsAsyncStreamUdpListener : clsAsyncStream
    {
        /// <summary>
        /// 当前的UdpClient
        /// </summary>
        public UdpClient currentUpdClient { get; set; }
        /// <summary>
        /// 本地端口
        /// </summary>
        public int localPort { get; set; }

        public IPEndPoint remoteIp { get; set; }

        public override void asyncThread()
        {
            currentUpdClient = new UdpClient(localPort);
            try
            {
                
                while (true)
                {
                    //不断监听并转发
                    IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
                    Byte[] receiveBytes = currentUpdClient.Receive(ref RemoteIpEndPoint);
                    remoteIp = new IPEndPoint(RemoteIpEndPoint.Address, RemoteIpEndPoint.Port);//保存远程地址
                    oppersiteStream.oppersiteRead(receiveBytes, 0, receiveBytes.Length);
                    Array.Clear(receiveBytes, 0, receiveBytes.Length);
                }
                
            }
            catch (Exception e)
            {
                System.Console.WriteLine("错误:"+e.Message);
                currentUpdClient.Close();
                //throw;
            }
            //base.asyncThread();
        }

        public override void oppersiteRead(byte[] buffer, int offset, int count)
        {
            if (currentUpdClient!=null)
            {
                //如下是复制出要发送的数据
                byte[] buf = new byte[count - offset];
                for (int i = 0 , j=offset; i < count-offset; i++,j++)
                {
                    buf[i] = buffer[j];
                }
                try
                {
                    currentUpdClient.Send(buf, buf.Length, remoteIp);
                }
                catch (Exception e)
                {
                    System.Console.WriteLine("不能发送UDP信息:"+e.Message);
                    currentUpdClient.Close();
                    //throw;
                }
                
            }
            //base.oppersiteRead(buffer, offset, count);
        }
        public override void Write(byte[] buffer, int offset, int count)
        {
            oppersiteRead(buffer, offset, count);
            //base.Write(buffer, offset, count);
        }
        
    }
    public class clsAsyncStreamUdpClient : clsAsyncStream
    {
        /// <summary>
        /// 当前的UdpClient
        /// </summary>
        public UdpClient currentUpdClient { get; set; }
        /// <summary>
        /// 本地端口
        /// </summary>
        public int localPort { get; set; }

        public IPEndPoint remoteIp { get; set; }

        private string _hostName;
        /// <summary>
        /// 目标
        /// </summary>
        public string hostName
        {
            get { return _hostName; }
            set { _hostName = value; }
        }

        private int _targetPort;
        /// <summary>
        /// 目标端口
        /// </summary>
        public int targetPort
        {
            get { return _targetPort; }
            set { _targetPort = value; }
        }

        public override void asyncThread()
        {
            currentUpdClient = new UdpClient(localPort);
            try
            {
                IPAddress ipAddress = Dns.GetHostEntry(hostName).AddressList[0];
                IPEndPoint ipRemoteEndPoint = new IPEndPoint(ipAddress,targetPort);
                remoteIp = new IPEndPoint(ipRemoteEndPoint.Address, ipRemoteEndPoint.Port);
                currentUpdClient.Connect(ipRemoteEndPoint);

                //不断的接收数据
                while (true)
                {
                    Byte[] receiveBytes = currentUpdClient.Receive(ref ipRemoteEndPoint);
                    oppersiteStream.oppersiteRead(receiveBytes, 0, receiveBytes.Length);
                    
                }

            }
            catch (Exception e)
            {
                System.Console.WriteLine("不能连接:"+e.Message);
                Environment.Exit(0);
                //throw;
            }
            
            //base.asyncThread();
        }

        public override void oppersiteRead(byte[] buffer, int offset, int count)
        {
            if (currentUpdClient != null)
            {
                //如下是复制出要发送的数据
                byte[] buf = new byte[count - offset];
                for (int i = 0, j = offset; i < count - offset; i++, j++)
                {
                    buf[i] = buffer[j];
                }
                try
                {
                    currentUpdClient.Send(buf, buf.Length);
                }
                catch (Exception e)
                {
                    System.Console.WriteLine("不能发送UDP信息:" + e.Message);
                    currentUpdClient.Close();
                    //throw;
                }

            }
            //base.oppersiteRead(buffer, offset, count);
        }

    }

    /// <summary>
    /// 发送文件的流
    /// </summary>
    public class clsAsyncStreamSendFile : clsAsyncStream
    {
        public clsAsyncStreamSendFile()
        {
            isTransferFile = true;//发送文件
        }
        public string fileName { get; set; }
        public override void asyncThread()
        {
            //发送文件
            //以二进制读取文件，然后转发，最后结束程序
            using (FileStream fs=new FileStream(fileName,FileMode.OpenOrCreate,FileAccess.Read))
            {
                //二进制读流
                using (BinaryReader br = new BinaryReader(fs))
                {
                    byte[] buf = new byte[bufSize];
                    for (int i = 0; i < fs.Length; i++)
                    {
                        Array.Clear(buf, 0, buf.Length);
                        int readlength;
                        readlength = br.Read(buf, 0, buf.Length);//读取
                        i += readlength;//加上偏移
                        oppersiteStream.oppersiteRead(buf, 0, readlength);//转发    
                        
                    }
                }
 
            }
            //传输结束后结束程序
            Environment.Exit(0);

            //base.asyncThread();
        }

    }

    /// <summary>
    /// 接受文件的
    /// </summary>
    public class clsAsyncStreamReceiveFile : clsAsyncStream
    {
        public clsAsyncStreamReceiveFile()
        {
            isTransferFile = true;//发送文件
        }
        public string fileName { get; set; }
        public override void oppersiteRead(byte[] buffer, int offset, int count)
        {
            using (FileStream fs = new FileStream(fileName, FileMode.Append, FileAccess.Write))
            {
                using (BinaryWriter bw = new BinaryWriter(fs))
                {
                    //写入文件
                    fs.Write(buffer, offset, count);
                }
            }
            //base.oppersiteRead(buffer, offset, count);
        }

    }
    /// <summary>
    /// shell
    /// </summary>
    public class clsAsyncStreamShell : clsAsyncStream
    {
        string strCurrentDir;//当前目录

        //这个类不用新开一个线程，
        public override void start()
        {


            //base.start();
        }
        /// <summary>
        /// 输入一个命令就返回
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        public override void oppersiteRead(byte[] buffer, int offset, int count)
        {
            //得到命令
            string strCmd = System.Text.Encoding.Default.GetString(buffer, offset, count);

            string strReturn = RunCmd(strCmd);

            byte[] buf = System.Text.Encoding.Default.GetBytes(strReturn);
            oppersiteStream.oppersiteRead(buf, 0, buf.Length);


        }

        private string RunCmd(string command)
        {
            //
            Process p = new Process();
            //Process類有一個StartInfo屬性，這個是ProcessStartInfo類，包括了一些屬性和方法，下面我們用到了他的幾個屬性：
            p.StartInfo.FileName = "cmd.exe";			  //設定程序名
            //p.StartInfo.Arguments = "/c " + command;	 //設定程式執行參數
            p.StartInfo.WorkingDirectory = strCurrentDir;//设定工作目录
            p.StartInfo.UseShellExecute = false;		  //關閉Shell的使用
            p.StartInfo.RedirectStandardInput = true;	//重定向標準輸入
            p.StartInfo.RedirectStandardOutput = true;  //重定向標準輸出
            p.StartInfo.RedirectStandardError = true;	//重定向錯誤輸出
            p.StartInfo.CreateNoWindow = true;			 //設置不顯示窗口
            p.Start();	//啟動
            p.StandardInput.WriteLine(command);		 //也可以用這種方式輸入要執行的命令
            p.StandardInput.WriteLine("exit");		  //不過要記得加上Exit要不然下一行程式執行的時候會當機
            string str= p.StandardOutput.ReadToEnd();		  //從輸出流取得命令執行結果
            string[] arrStr = str.Split('\n');
            strCurrentDir = arrStr[arrStr.Length - 3];//倒数第二行就是啦
            strCurrentDir= strCurrentDir.Remove(strCurrentDir.Length - 2);
            string strReturn = string.Empty;
            //我只要到倒数第三行就可以啦。
            for (int i = 0; i < arrStr.Length - 2; i++)
            {
                strReturn += arrStr[i]+"\n";
            }

            p.WaitForExit();//避免死锁要这个
            p.Close();
            return strReturn;
        }

       
    }

}
